import os
import httplib
import collections
import sys
import urllib
from prettytable import PrettyTable
import json

_commands = ["image", "volume", "flavor", "server", "network", "port"]

def get_commands_mapping():
    commands_mapping = collections.OrderedDict()
    commands_mapping["image"] = ImageCommand
    commands_mapping["volume"] = VolumeCommand
    commands_mapping["flavor"] = FlavorCommand
    commands_mapping["server"] = ServerCommand
    commands_mapping["network"] = NetworkCommand
    commands_mapping["port"] = PortCommand
    return commands_mapping


def usage(command=None):
    print "Usage:"
    if command:
        if type(command) == type(AbstractCommand) and issubclass(command, AbstractCommand):
            print command.__doc__,
        else:
            print get_commands_mapping()[command].__doc__,
    else:
        for _command in get_commands_mapping().values():
            print _command.__doc__,
    exit(0)


class UsageException(Exception):
    pass

class AbstractCommand(object):

    actions = []
    fields = []

    def __init__(self):
        STACK_HOST = os.environ.get("STACK_HOST")
        STACK_PORT = os.environ.get("STACK_PORT")
        if not(STACK_HOST and STACK_PORT):
            print "Not Set Environ Variable STACK_HOST and STACK_PORT"
            exit(1)
        self.httpclient = httplib.HTTPConnection(STACK_HOST, STACK_PORT, timeout=10)
        self.table = PrettyTable()
        self.table.field_names = self.fields
        self.headers = {'content-type': 'application/json'}

    def get_row(self, data):
        return map(lambda x: data[x], self.fields)

    def _get(self, uri):
        self.httpclient.request("GET", uri)
        response = self.httpclient.getresponse()
        if response.status == 200:
            return json.loads(response.read())
        else:
            raise Exception()

    def _post(self, uri, **params):
        self.httpclient.request("POST", uri, json.dumps(params), headers=self.headers)
        response = self.httpclient.getresponse()
        if response.status == 200:
            return json.loads(response.read())
        else:
            raise Exception()
    
    def _delete(self, uri, **params):
        self.httpclient.request("DELETE", uri, json.dumps(params), headers=self.headers)
        response = self.httpclient.getresponse()
        if response.status == 200:
            return json.loads(response.read())
        else:
            raise Exception()

    def execute(self, action, *args, **kwargs):
        if action in self.actions:
            try:
                getattr(self, action)(*args, **kwargs)
            except UsageException:
                usage(self.__class__)


class ImageCommand(AbstractCommand):
    """
    stack image list
    stack image create --file file_name name
    stack image delete uuid
    """
    actions = ["list", "create", "delete"]
    fields = ["id", "uuid", "name", "status", "checksum"]

    def list(self, *args, **kwargs):
        images = self._get("/images")
        for image in images:
            row = self.get_row(image)
            self.table.add_row(row)
        print self.table

    def create(self, *args, **kwargs):
        if len(args) == 3 and  args[0] == "--file":
            self._post("/images", **{"name": args[2]})
        else:
            raise UsageException()

    def delete(self, *args, **kwargs):
        if len(args) == 1:
            self._delete("/images", **{"id": args[0]})
        else:
            raise UsageException()

class VolumeCommand(AbstractCommand):
    """
    stack volume list
    stack volume create --sie 1 name
    stack volume delete uuid
    """
    actions = ["list", "create", "delete"]

    def execute(self, action, *args, **kwargs):
        pass


class FlavorCommand(AbstractCommand):
    """
    stack flavor list
    stack flavor create --vcpu 1 --memory 1024 --root 1 name
    stack flavor delete uuid
    """
    actions = ["list", "create", "delete"]
    fields = ["id", "uuid", "name", "vcpu", "memory", "root"]

    def list(self, *args, **kwargs):
        flavors = self._get("/flavors")
        for flavor in flavors:
            row = self.get_row(flavor)
            self.table.add_row(row)
        print self.table

    def create(self, *args, **kwargs):
        if len(args) == 7:
            data = {}
            for i in range(0, 6, 2):
                data[args[i][2:]] = int(args[i+1])
            data["name"] = args[6]
            self._post("/flavors", **data)
        else:
            raise UsageException()

    def delete(self, *args, **kwargs):
        if len(args) == 1:
            self._delete("/flavors", **{"id": args[0]})
        else:
            raise UsageException()

class ServerCommand(AbstractCommand):
    """
    stack server list
    stack server create --flavor flavor --image image --network network name
    stack server delete uuid
    """

    def execute(self, action, *args, **kwargs):
        pass


class NetworkCommand(AbstractCommand):
    """
    stack network list
    stack network create 
    stack network delete uuid
    """

    def execute(self, action, *args, **kwargs):
        pass


class PortCommand(AbstractCommand):
    """
    stack port list
    stack port create
    stack port delete uuid
    """

    def execute(self, action, *args, **kwargs):
        pass


def main():
    if len(sys.argv) == 1:
        usage()
    if len(sys.argv) == 2:
        if sys.argv[1] in _commands:
            usage(sys.argv[1])
        else:
            usage()
    if len(sys.argv) >= 3:
        if sys.argv[1] in _commands:
            command = get_commands_mapping()[sys.argv[1]]
            if sys.argv[2] in command.actions:
                command().execute(sys.argv[2], *sys.argv[3:])
            else:
                usage(sys.argv[1])
        else:
            usage()


main()
